import re

import logging


from django import http


from django.http import HttpResponse
from django.shortcuts import render, redirect

# Create your views here.
from django.urls import reverse
from django.views import View


from django.contrib.auth import login, authenticate, logout

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.users.models import User, Address
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin

'''
一.把需求写下来
    前端：收集 用户名，密码，确认密码，手机号
    后端：实现注册

二.详细分析后段逻辑
    1.先接收数据
    2.验证数据（做后端开发的 不相信前端提交的任何数据）
        2.1 先验证必传数据(如果缺少，那就别验证了)
        2.2 验证用户名是否符合规则
        2.3 验证密码是否符合规则
        2.4 验证确认密码和密码是否一致
        2.5 验证手机号
    3.数据入库
        3.1 如果我们使用基础学习的模型保存 密码没有加密
            我们可以直接调用  系统的方法来完成密码加密 creat_user
    4.返回相应
三.确认请求方式和路由
    POST  /register

    注册成功后 会跳转到登录页面
    注册成功后  默认登录（保持会话的一致性  设置cookie或者是session）
'''



class RegisterView(View):

    def get(self,request):

        return render(request, 'register.html')
    def post(self,request):
        # 1.先接收数据

        data = request.POST
        username = data.get("username")
        password = data.get("password")
        password2 = data.get("password2")
        mobile = data.get("mobile")
        # 2.验证数据（做后端开发的
        # 不相信前端提交的任何数据）

        # 2.1先验证必传数据(如果缺少，那就别验证了)
        if not all(["username", "password","password2", "mobil"]):
            return http.HttpResponseBadRequest("缺少参数")
        # 2.2 验证用户名是否符合规则    判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return http.HttpResponseBadRequest("用户名不合法")
        # 2.3 验证密码是否符合规则  判断是否是8-20个字符
        if not re.match(r'^[a-zA-Z0-9]{8,20}$',password):
            return http.HttpResponseBadRequest("密码输入不合法")
        # 2.4 验证确认密码和密码是否一致

        if password != password2:
            return http.HttpResponseBadRequest("两次密码不一致，请重新输入")

        # 2.5 验证手机号
        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return http.HttpResponseBadRequest("手机号输入不合法")

        # 3.数据入库
        # 3.1 如果我们使用基础学习的模型保存  密码没有加密
        # 我们可以直接调用   系统的方法来完成密码加密  create_user
        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
              logst = logging.getLogger("django")
              logst.error(e)

        # 默认登录
        # login(request,user)

        # 4. 返回相应
        # return HttpResponse("注册成功")
        return redirect(reverse('contents:index'))


'''
一.把需求写下来
    作为用户会干什么:
    前段收集什么数据:
    后端实现什么功能：
二.详细分析后端逻辑
三.确定请求方式和路由




一.把需求写下来
    作为用户会干什么: 输入完用户名之后，会输入密码
    前段收集什么数据： 当光标失去焦点之后，获取到用户名 提交给后端
    后端实现什么功能：  接受这个用户名，根据用户名进行查询
                    如果查询的数量为1 说明存在
                    如果查询的数量为0 说明不存在


二.详细分析后端逻辑

    1.接受这个用户名
    2.根据用户名进行查询，获取数量
    3.返回数据


三.确定请求方式和路由     (?p<name>)   分组起别名
                      (?P=name)   引用别名为name分组匹配到的字符串
    GET  register/count/?name=xxx
         /usernames/(?P<username>[a-zA-Z0-9_-]{5,20})/count/  count表示usernames的数量 没有太大实际的作用
    POST  register/count/

'''

# 用户名
class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        """
        :param request: 请求对象
        :param username: 用户名
        :return: JSON
        """
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code':0, 'errmsg': 'OK', 'count': count})

# 手机号
class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param request: 请求对象
        image_code_client = reqeust.GET.get('image_code')
        uuid = reqeust.GET.get('uuid')
        :param mobile: 手机号
        :return: JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': 0, 'errmsg': 'OK', 'count': count})


class LoginView(View):
    """用户名登录"""

    def get(self, request):
        return render(request,'login.html')

    def post(self, request):
        """
                       实现登录逻辑
                       :param request: 请求对象
                       :return: 登录结果
                       """
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        remembered = request.POST.get('remembered')
        next = request.POST.get('next')

        if not all([username, password]):
            return http.HttpResponseBadRequest('缺少必传参数')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseBadRequest('请输入正确的用户名或手机号')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseBadRequest('密码不符合规则')


        user = authenticate(username=username, password=password)

        if user is None:
            return  http.HttpResponseBadRequest('用户名或密码错误')

        # 保持登录状态
        login(request,user)
        # 判断是否登陆记住登陆状态
        if remembered != 'on':
        #     # 没有记住用户：浏览器会话结束就过期
            request.session.set_expiry(0)
        else:
        #     # 记住用户：None表示两周后过期
            request.session.set_expiry(None)

        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))


        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        # 合并购物车中的数据
        response=merge_cart_cookie_to_redis(request,user,response)


        return response


class LogoutView(View):
#     """退出登录"""
#
    def get(self, request):
#         """实现退出登录逻辑"""
#         # 清理session
#
        logout(request)
#         # 退出登录，重定向到登录页
        response = redirect(reverse('contents:index'))
#         # 退出登录时清除cookie中的username
        response.delete_cookie('username')
#
        return response


# 用户中心必须是登录过后才能进去  未通过则不能进去 跳转到登陆界面
from django.contrib.auth.mixins import LoginRequiredMixin


class UserCenterView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request, 'user_center_info.html', context=context)

from celery_tasks.email.tasks import send_verify_email
import json

# 当前我们是和前端进行ajax交互
# 交互的数据 应该都是json数据
# 但是LoginRequiredMixin 返回的并不熟json数据,而是重定向
# 我们应该你返回前端json数据
class EmailView(LoginRequiredJSONMixin,View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        body =request.body
        body_str = body.decode()
        data = json.loads(body_str)
        email = data.get('email')

        # 校验参数
        if email is None:
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不全'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数不全'})

        # 赋值email字段
        user = request.user
        try:
            user.email = email
            user.save()
        except Exception as e:
            import logging
            logger = logging.getLevelName('django')
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})
        # 导入itsdangesrous
        from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
        from meiduoproject import settings

        s = Serializer(secret_key=settings.SECRET_KEY, expires_in =3600)

        data ={'id': user.id}
        # 加密
        token = s.dumps(data).decode()
        verify_url = 'http://www.meiduo.site:8000/email_active/?token=' + token
        send_verify_email.delay(email, verify_url)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg':'添加成功'})


# subject 邮件标题
# message 普通邮件正文，普通字符串
# from_email 发件人
# recipient_list 收件人列表
# html_message 多媒体邮件正文，可以是html字符串

class EmailActiveView(View):
    def get(self,request):
        token = request.GET.get('token')
        if token is None:
            return http.HttpResponseBadRequest("参数错误")
        user_id =check_verify_email_token(token)
        if user_id is None:
            return http.HttpResponseBadRequest("参数错误")
        try:
            user = User.objects.get(id=user_id)
        except Exception:
            return http.HttpResponseBadRequest("没有此用户")
        user.email_active=True
        user.save()
        return redirect(reverse('users:center'))




from apps.users.utils import check_verify_email_token

class VerifyEmailView(View):
    """验证邮箱"""

    def get(self, request):
        """实现邮箱验证逻辑"""
        # 接收参数
        token = request.GET.get('token')

        # 校验参数：判断token是否为空和过期，提取user
        if not token:
            return http.HttpResponseBadRequest('缺少token')

        user = check_verify_email_token(token)
        if not user:
            return http.HttpResponseBadRequest('无效的token')

        # 修改email_active的值为True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            import logging
            logger = logging.getLogger('django')
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')

        # 返回邮箱验证结果
        return redirect(reverse('users:center'))


from django.views import View


class AddressView(LoginRequiredMixin,View):
    """用户收货地址"""

    def get(self, request):
        # 获取查询条件
        user = request.user
        # 根据查询条件查询数据
        addresses = Address.objects.filter(user=user,is_deleted=False)
        # 返回相应
        # 因为地址页面有动态数据删除和添加等功能，所以我们借助与vue
        # 需要将对象转换位字典列表、
        addresses_list=[]
        for address in addresses:
            addresses_list.append({
                 "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "province_id":address.province_id,
                "city": address.city.name,
                "city_id":address.city_id,
                "district": address.district.name,
                "district_id":address.district_id,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })

        context = {
            'addresses':addresses_list,
            'default_address_id':user.default_address_id
        }
        return render(request, 'user_center_site.html',context=context)


# 添加
class CreateAddressView(View):
    def post(self,request):
        # json.loads 讲字符串转换为字典    json.load 将json格式的字符串转换为字典

        count = Address.objects.filter(user=request.user).count()
        if count >= 20:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        import json
        json_dict = json.loads(request.body.decode())
        user = request.user


        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if not all([receiver,province_id,city_id,district_id,place,mobile]):
            return http.HttpResponseBadRequest("缺少必传参数")
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest("电话号码输入错误")
        if re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
            return http.HttpResponseBadRequest('固定电话输入有误')
        if  re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseBadRequest('电子邮件输入错误')

        try:
            # 保存入库
            address = Address.objects.create(user=request.user,
                                             title=receiver,
                                             receiver=receiver,
                                             province_id=province_id,
                                             city_id=city_id,
                                             district_id=district_id,
                                             place=place,
                                             mobile=mobile,
                                             tel=tel,
                                             email=email
                                             )
            if request.user.default_address:
                address = request.user.default_address
                request.user.save()

        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        address = {
            "id":address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
            }
        return http.JsonResponse({'code':'ok','errmsg':"新增地址成功",'address':address})


# 更新数据  # 删除数据
class UpdateAddresssView(View):
    def put(self,request,address_id):

        import json
        json_dict = json.loads(request.body.decode())
        user = request.user


        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if not all([receiver,province_id,city_id,district_id,place,mobile]):
            return http.HttpResponseBadRequest("缺少必传参数")
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest("电话号码输入错误")
        if re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
            return http.HttpResponseBadRequest('固定电话输入有误')
        if  re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseBadRequest('电子邮件输入错误')

        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

        except Exception:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'更新失败'})

        # 返回响应
        # 需要将更新之后最新的数据返回给前端
        address = Address.objects.get(id=address_id)
        address = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'更新成功','address': address})


    #删除操作
    def delete(self,request,address_id):
        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted =True
            address.save()
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': "删除失败"})

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除成功'})


